package io.renren.util;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

/**
 * 工具类
 * Created by Linus_Xie on 2016/7/27.
 */
public class HexUtils {

  /**
   * byte——>String
   *
   * @param src
   * @return
   */
  public static final String bytesToHexString(byte[] src) {
    StringBuilder stringBuilder = new StringBuilder("");
    if (src == null || src.length <= 0) {
      return null;
    }
    for (int i = 0; i < src.length; i++) {
      int v = src[i] & 0xFF;
      String hv = Integer.toHexString(v);
      if (hv.length() < 2) {
        stringBuilder.append(0);
      }
      stringBuilder.append(hv);
    }
    return stringBuilder.toString();
  }
  public static final String intsToHexString(int[] src) {
    StringBuilder stringBuilder = new StringBuilder("");
    if (src == null || src.length <= 0) {
      return null;
    }
    for (int i = 0; i < src.length; i++) {
      int v = src[i];
      String hv = Integer.toHexString(v);
      if (hv.length() < 2) {
        stringBuilder.append(0);
      }
      stringBuilder.append(hv);
    }
    return stringBuilder.toString();
  }
  /**
   * 数组截取：从source的offset开始获取len个长度的byte生成的len的byte[]
   *
   * @param source
   * @param offset
   * @param len
   * @return
   */
  public static final byte[] getByteArrayByLength(byte[] source, int offset, int len) {
    byte[] newData = new byte[len];
    try {
      for (int i = offset; i < offset + len; i++) {
        if (i >= source.length) {
          break;
        }
        newData[i - offset] = source[i];
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return newData;
  }
  public static final int[] getIntArrayByLength(int[] source, int offset, int len) {
    int[] newData = new int[len];
    try {
      for (int i = offset; i < offset + len; i++) {
        if (i >= source.length) {
          break;
        }
        newData[i - offset] = source[i];
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return newData;
  }

  /**
   * 通过byte数组取得float
   *
   * @param bb
   * @param index
   * @return
   */
  public static float getFloat(byte[] bb, int index) {
    int l;
    l = bb[index + 0];
    l &= 0xff;
    l |= ((long) bb[index + 1] << 8);
    l &= 0xffff;
    l |= ((long) bb[index + 2] << 16);
    l &= 0xffffff;
    l |= ((long) bb[index + 3] << 24);
    return Float.intBitsToFloat(l);
  }

  /**
   * short转换成byte数组
   *
   * @param s
   * @return
   */
  public static final byte[] shortToBytes(short s) {//01e2
    byte[] shortBuf = new byte[2];
    for (int i = 0; i < 2; i++) {
      int offset = (shortBuf.length - 1 - i) * 8;
      shortBuf[i] = (byte) ((s >>> offset) & 0xff);
    }
    return shortBuf;
  }

  public static void intToByte_LH(int intVal, byte[] b, int offset) {
    b[0 + offset] = (byte) (intVal & 0xff);
    b[1 + offset] = (byte) (intVal >> 8 & 0xff);
    b[2 + offset] = (byte) (intVal >> 16 & 0xff);
    b[3 + offset] = (byte) (intVal >> 24 & 0xff);
  }

  public static byte[] intToByte_LH(int intVal) {
    byte[] b = new byte[4];
    b[0] = (byte) (intVal & 0xff);
    b[1] = (byte) (intVal >> 8 & 0xff);
    b[2] = (byte) (intVal >> 16 & 0xff);
    b[3] = (byte) (intVal >> 24 & 0xff);
    return b;
  }

  public static byte[] shortToByteArray(short s, boolean littleEndian) {
    //littleEndian:true 高位在前 false 低位在前
    byte[] bytes = new byte[2];
    for (int i = 0; i < 2; i++) {
      int i1 = (littleEndian ? i : (1 - i)) << 3;
      //int i1 = (littleEndian?i:(1-i))*8;
      bytes[i] = (byte) ((s >> i1) & 0xff);
    }
    return bytes;
  }

  /**
   * short 转 byte 高低位互换
   *
   * @param s
   * @return byte[]
   */
  public static final byte[] shortToByte(short s) {//e201
    byte[] shortBuf = new byte[2];
    shortBuf[0] = (byte) (s & 0xff);
    shortBuf[1] = (byte) ((s >>> 8) & 0xff);
    return shortBuf;
  }
  /**
   * short 转 byte 高低位互换
   *
   * @param s
   * @return byte[]
   */
  public static final byte[] shortToByteHL(short s) {//e201
    byte[] shortBuf = new byte[1];
    shortBuf[0] = (byte) (s & 0xff);
//    shortBuf[1] = (byte) ((s >>> 8) & 0xff);
    return shortBuf;
  }

  public static String turn2to16(String str) {
    String sum = "";

    int t = str.length() % 4;
    if (t != 0) {
      for (int i = str.length(); i - 4 >= 0; i = i - 4) {
        String s = str.substring(i - 4, i);
        int tem = Integer.parseInt(String.valueOf(s), 2);
        sum = Integer.toHexString(tem).toUpperCase() + sum;
      }
      String st = str.substring(0, t);

      int tem = Integer.parseInt(String.valueOf(st), 2);
      sum = Integer.toHexString(tem).toUpperCase() + sum;

    } else {
      for (int i = str.length(); i - 4 >= -1; i = i - 4) {
        String s = str.substring(i - 4, i);
        int tem = Integer.parseInt(String.valueOf(s), 2);
        sum = Integer.toHexString(tem).toUpperCase() + sum;
      }
    }
    return sum;
  }

  /**
   * int转byte数组
   *
   * @param num
   * @return
   */
  public static byte[] intTo4Byte(int num) {
    byte[] bytes = new byte[4];
    bytes[0] = (byte) ((num >> 24) & 0xff);
    bytes[1] = (byte) ((num >> 16) & 0xff);
    bytes[2] = (byte) ((num >> 8) & 0xff);
    bytes[3] = (byte) (num & 0xff);
    return bytes;
  }


  /**
   * 判断两个byte数组是否相等
   *
   * @param myByte
   * @param otherByte
   * @return
   */
  public static final boolean checkEqual(byte[] myByte, byte[] otherByte) {
    boolean b = false;
    int len = myByte.length;
    if (len == otherByte.length) {
      for (int i = 0; i < len; i++) {
        if (myByte[i] != otherByte[i]) {
          return b;
        }
      }
      b = true;
    }
    return b;
  }

  /**
   * bytes字符串转换为Byte值
   *
   * @param src src Byte字符串，每个Byte之间没有分隔符
   * @return byte[]
   * <p>
   * 89860070111257004158--->0x89 0x86.... 0
   */
  public static byte[] hexStr2Bytes(String src) {
    int m = 0, n = 0;
    int l = src.length() / 2;
    byte[] ret = new byte[l];
    for (int i = 0; i < l; i++) {
      m = i * 2 + 1;
      n = m + 1;
      ret[i] = (byte) Integer.parseInt(src.substring(i * 2, m) + src.substring(m, n), 16);
    }
    return ret;
  }

  public static int[] hexStr2Ints(String src) {
    int m = 0, n = 0;
    int l = src.length() / 2;
    int[] ret = new int[l];
    for (int i = 0; i < l; i++) {
      m = i * 2 + 1;
      n = m + 1;
      ret[i] = Integer.parseInt(src.substring(i * 2, m) + src.substring(m, n), 16);
    }
    return ret;
  }
  /**
   * 若都不为空，将arrSrc2添加到arrSrc1的末尾组合成新的byte数组
   *
   * @param target
   * @param source
   * @return
   */
  public static final byte[] append(byte[] target, byte[] source) {
    if (source == null) {
      return target;
    }
    byte[] arrDes;
    if (target != null) {
      arrDes = new byte[target.length + source.length];
      System.arraycopy(target, 0, arrDes, 0, target.length);
      System.arraycopy(source, 0, arrDes, target.length, source.length);
    } else {
      arrDes = new byte[source.length];
      System.arraycopy(source, 0, arrDes, 0, source.length);
    }
    return arrDes;
  }

  /**
   * byte数组转换为无符号short整数
   *
   * @param bytes byte数组
   * @return short整数
   */
  public static int byte2ToUnsignedShort(byte[] bytes) {
    return byte2ToUnsignedShort(bytes, 0);
  }

  /**
   * byte数组转换为无符号short整数
   *
   * @param bytes byte数组
   * @param off   开始位置
   * @return short整数
   */
  public static int byte2ToUnsignedShort(byte[] bytes, int off) {
    int high = bytes[off];
    int low = bytes[off + 1];
    return (high << 8 & 0xFF00) | (low & 0xFF);
  }

  public static int getUnsignedByte(byte data) {      //将data字节型数据转换为0~255 (0xFF 即BYTE)。
    return data & 0x0FF;
  }

  public static int getUnsignedByte(short data) {
    //将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。
    return data & 0x0FFFF;
  }

  // 无符号整型转化为字节数组
  public static byte[] unsigned_int_2byte(long length) {
    byte[] targets = new byte[4];
    for (int i = 0; i < 4; i++) {
      int offset = (targets.length - 1 - i) * 8;
      targets[i] = (byte) ((length >>> offset) & 0xff);
    }
    return targets;
  }

  public static long getUnsignedInt(int data) {     //将int数据转换为0~4294967295 (0xFFFFFFFF即DWORD)。
    return data & 0x0FFFFFFFF;
  }

  /**
   * 将一个单字节的byte转换成32位的int
   *
   * @param b byte
   * @return convert result
   */
  public static int unsignedByteToInt(byte b) {
    return (int) b & 0xFF;
  }

  /**
   * byte数组转换为int整数
   *
   * @param bytes byte数组
   * @param off   开始位置
   * @return int整数
   */
  public static int byte4ToInt(byte[] bytes, int off) {
    int b0 = bytes[off] & 0xFF;
    int b1 = bytes[off + 1] & 0xFF;
    int b2 = 0;
    if (bytes.length > 2) {
      b2 = bytes[off + 2] & 0xFF;
    }
    int b3 = 0;
    if (bytes.length > 3) {
      b3 = bytes[off + 3] & 0xFF;
    }
    return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
  }


  /**
   * byte数组转换成Short
   *
   * @param b
   * @return
   */
  public static final short bytesToShort(byte[] b) {
    return (short) ((b[0] << 8) + (b[1] & 0xFF));
  }

  // long类型转成byte数组
  public static byte[] longToByte(long number) {
    long temp = number;
    byte[] b = new byte[6];
    for (int i = 0; i < b.length; i++) {
      b[i] = new Long(temp & 0xff).byteValue();// 将最低位保存在最低位
      temp = temp >> 8; // 向右移8位
    }
    return b;
  }

  public static byte[] byteChange(byte[] a) {
    a[0] = (byte) (a[0] + a[1]);
    a[1] = (byte) (a[0] - a[1]);
    a[0] = (byte) (a[0] - a[1]);
    return a;
  }

//  public static final byte[] intTobyte2(int s) {
//    byte[] shortBuf = new byte[1];
//    shortBuf[0] = (byte) (s & 0xff);
//    return shortBuf;
//  }

  public static final byte[] intTo2ByteHL(int num) {
    byte[] shortBuf = new byte[2];
    shortBuf[1] = (byte) (num & 0xff);
    shortBuf[0] = (byte) ((num >>> 8) & 0xff);
    return shortBuf;
  }

  public static final byte[] intTo2Byte(int num) {
    byte[] shortBuf = new byte[2];
    shortBuf[0] = (byte) (num & 0xff);
    shortBuf[1] = (byte) ((num >>> 8) & 0xff);
    return shortBuf;
  }

  public static String HL_Transposition(String s) {
    String ret = "";
    String sA = s.substring(0, 2);
    String sB = s.substring(2);
    int A = Integer.parseInt(sA, 16);
    int B = Integer.parseInt(sB, 16);
    if (A > B) {
      ret = sB + sA;
    }
    return ret;
  }

  public static byte[] HL_Transposition(byte[] s) {
    byte temp; // 记录临时中间值
    int size = s.length; // 数组大小
    for (int i = 0; i < size - 1; i++) {
      for (int j = i + 1; j < size; j++) {
        if (s[i] < s[j]) { // 交换两数的位置
          temp = s[i];
          s[i] = s[j];
          s[j] = temp;
        }
      }
    }
    return s;
  }

  public static void shortToByte_LH(short shortVal, byte[] b, int offset) {
    b[0 + offset] = (byte) (shortVal & 0xff);
    b[1 + offset] = (byte) (shortVal >> 8 & 0xff);
  }

  public static void shortToByte_LHUnsigned(short shortVal, byte[] b, int offset) {
    b[0 + offset] = (byte) (shortVal & 0xFF00);
    b[1 + offset] = (byte) (shortVal >> 8 & 0xFF00);
  }


  public static int byteToShort_HLUnsigned(byte[] b, int offset) {
    short result;
    result = (short) (((b[offset + 1]) << 8) & 0xff00 | b[offset] & 0x00ff);
    return getUnsignedByte(result);
  }

  // 读取2个字节转为无符号整型
  public static int shortbyte2int(byte[] res) {
    DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(res));
    int a = 0;
    try {
      a = dataInputStream.readUnsignedShort();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return a;
  }

  public static int byteToShort_LHUnsigned(byte[] b, int offset) {
    short result;
    result = (short) (((b[offset]) << 8) & 0xff00 | b[offset + 1] & 0x00ff);
    return getUnsignedByte(result);
  }

  public static short byteToShort_HL(byte[] b, int offset) {
    short result;
    result = (short) (((b[offset + 1]) << 8) & 0xff00 | b[offset] & 0x00ff);
    return result;
  }

  public static short byteToShort_LH(byte[] b, int offset) {
    short result;
    result = (short) (((b[offset]) << 8) & 0xff00 | b[offset + 1] & 0x00ff);
    return result;
  }

  public static int byteToInt_HL(byte[] b, int offset) {
    int result;
    result = (((b[3 + offset] & 0x00ff) << 24) & 0xff000000)
        | (((b[2 + offset] & 0x00ff) << 16) & 0x00ff0000)
        | (((b[1 + offset] & 0x00ff) << 8) & 0x0000ff00)
        | ((b[0 + offset] & 0x00ff));
    return result;
  }

  public static int byteToInt_LH(byte[] b, int offset) {
    int result;
    result = (((b[0 + offset] & 0x00ff) << 24) & 0xff000000)
        | (((b[1 + offset] & 0x00ff) << 16) & 0x00ff0000)
        | (((b[2 + offset] & 0x00ff) << 8) & 0x0000ff00)
        | ((b[3 + offset] & 0x00ff));
    return result;
  }

  /**
   * 本地校验位
   *
   * @param pData
   * @return
   */
  public static final byte checkCode(byte[] pData) {
    int len = pData.length;
    long dataSum = 0;
    byte rByte = 0;
    int rByteBu = 0;
    for (int i = 0; i < len; i++) {
      dataSum ^= pData[i];
    }
    rByteBu = (int) (dataSum % 256) ^ 0xff;
    rByte = Integer.valueOf(rByteBu).byteValue();
    return rByte;
  }

  /**
   * 7e 和 7d 转义成7d 5e  和  7d  和 5d
   *
   * @param intoData
   * @return
   */
  public static final byte[] transferByte(byte[] intoData) {
    byte[] arrDes = null;
    int len = intoData.length;
    for (int i = 0; i < len; i++) {
      if (intoData[i] == 0x7E) {
        byte[] temp = new byte[2];
        temp[0] = 0x7D;
        temp[1] = 0x5E;
        arrDes = HexUtils.append(arrDes, temp);
      } else if (intoData[i] == 0x7d) {
        byte[] temp = new byte[2];
        temp[0] = 0x7D;
        temp[1] = 0x5d;
        arrDes = HexUtils.append(arrDes, temp);
      } else {
        byte[] temp = new byte[1];
        temp[0] = intoData[i];
        arrDes = HexUtils.append(arrDes, temp);
      }
    }
    return arrDes;
  }

  /**
   * 将7dH 5eH 和7dH 5dH分别反转义成 7eH和7dH
   *
   * @param intoData
   * @return
   */
  public static byte[] redByte2(byte[] intoData) {
    byte[] arrDes = null;
    int len = intoData.length;
    for (int i = 0; i < len; i++) {
      if (intoData[i] == 0x7d && intoData[i + 1] == 0x5e) {
        byte[] temp = new byte[1];
        temp[0] = 0x7e;
        arrDes = HexUtils.append(arrDes, temp);
        ++i;
      } else if (intoData[i] == 0x7d && intoData[i + 1] == 0x5d) {
        byte[] temp = new byte[1];
        temp[0] = 0x7d;
        arrDes = HexUtils.append(arrDes, temp);
        ++i;
      } else {
        byte[] temp = new byte[1];
        temp[0] = intoData[i];
        arrDes = HexUtils.append(arrDes, temp);
      }
    }
    return arrDes;
  }

  /**
   * 将byte[]转为各种进制的字符串
   *
   * @param bytes byte[]
   * @param radix 基数可以转换进制的范围，从Character.MIN_RADIX到Character.MAX_RADIX，超出范围后变为10进制
   * @return 转换后的字符串
   */
  public static String binary(byte[] bytes, int radix) {
    return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
  }

  public static String hexString2binaryString(String hexString) {
    if (hexString == null || hexString.length() % 2 != 0)
      return null;
    String bString = "", tmp;
    for (int i = 0; i < hexString.length(); i++) {
      tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));
      bString += tmp.substring(tmp.length() - 4);
    }
    return bString;
  }

  public static String binaryString2hexString(String bString) {
    if (bString == null || bString.equals("") || bString.length() % 8 != 0)
      return null;
    StringBuffer tmp = new StringBuffer();
    int iTmp = 0;
    for (int i = 0; i < bString.length(); i += 4) {
      iTmp = 0;
      for (int j = 0; j < 4; j++) {
        iTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1);
      }
      tmp.append(Integer.toHexString(iTmp));
    }
    return tmp.toString();
  }

  /**
   * 反转
   */
  public static byte[] reverse(byte[] bytes) {
    byte[] data = null;
    for (int i = bytes.length; i > 0; i--) {
      byte[] aa = getByteArrayByLength(bytes, i - 1, 1);
      data = append(data, aa);
    }
    return data;
  }

  public static String hexToAscii(String s) {
    byte[] baKeyword = new byte[s.length() / 2];
    for (int i = 0; i < baKeyword.length; i++) {
      baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(
          i * 2, i * 2 + 2), 16));
    }
    try {
      return new String(baKeyword, "utf-8");
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    return null;
  }

  /**
   * cs校验
   * @param data
   * @return
   */
  public static String makeChecksum(String data) {
    if (data == null || data.equals("")) {
      return "";
    }
    int total = 0;
    int len = data.length();
    int num = 0;
    while (num < len) {
      String s = data.substring(num, num + 2);
      total += Integer.parseInt(s, 16);
      num = num + 2;
    }
    /**
     * 用256求余最大是255，即16进制的FF
     */
    int mod = total % 256;
    String hex = Integer.toHexString(mod);
    len = hex.length();
    // 如果不够校验位的长度，补0,这里用的是两位校验
    if (len < 2) {
      hex = "0" + hex;
    }
    return hex;
  }
  /**
   * cs校验
   * @param data
   * @return
   */
  public static int makeChecksum(byte[] data) {
    if (data == null || data.length==0) {
      return 0;
    }
    int total = 0;
    for (int i = 0; i < data.length; i++) {
      total += data[i] & 255;
    }
    /**
     * 用256求余最大是255，即16进制的FF
     */
    int mod = total % 256;
    return mod;
  }


  // 转化十六进制编码为字符串
  public static String toStringHex1(String s) {
    byte[] baKeyword = new byte[s.length() / 2];
    for (int i = 0; i < baKeyword.length; i++) {
      try {
        baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(
            i * 2, i * 2 + 2), 16));
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    try {
      s = new String(baKeyword, "utf-8");
    } catch (Exception e1) {
      e1.printStackTrace();
    }
    return s;
  }
  public static int CRC16_XMODEM(byte[] buffer) {
    /* StringUtil.getByteArrayByString();*/

    int wCRCin = 0x0000; // initial value 65535
    int wCPoly = 0x1021; // 0001 0000 0010 0001 (0, 5, 12)
    for (byte b : buffer) {
      for (int i = 0; i < 8; i++) {
        boolean bit = ((b >> (7 - i) & 1) == 1);
        boolean c15 = ((wCRCin >> 15 & 1) == 1);
        wCRCin <<= 1;
        if (c15 ^ bit)
          wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xffff;
    return wCRCin ^= 0x0000;
  }
  public static void main(String[] args) {
    String s = "000000018d80db2e2085cadb5fa68fdd664de4338908c707d9b808d23040df70ac3d0cde93fd3e6c42545ac0e95b195cf414a85c31d2605904d3c0d66a9f4ea2326749d6a7bc1aeb797ea7be38245267854a299f3c196322ef4968ac94729adc2622d928c95729ed152fdaed9bcb1885435f7833e6692f15b55f1b192afd1a563c65b1796b17d1b4ac893b9e951b0fc26bdf1a4c43d65808ace605a7710e28a50195465714cc03c62ae0c304910f74652170713321d5522193e83a333a6500e06c56e7a2";
    int i = CRC16_XMODEM(HexUtils.hexStr2Bytes(s));
    System.out.println(HexUtils.bytesToHexString(HexUtils.intTo2Byte(i)));
//    int i = 32;
//    byte b = (byte) i;
//    System.out.println(bytesToHexString(new byte[]{b}));
//    String s = "20210730";
//    byte[] bytes = hexStr2Bytes(s);
//    System.out.println(bytesToHexString(bytes));
//    String s = "6901101FE2323032313034303831373532333320203447374e30394c56303059390101";
//    System.out.println(HexUtils.makeChecksum(s));
  }
}
